/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/commons/json/parser/deserializer/ASMDeserializerFactory.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: ASMDeserializerFactory.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (周一, 02 七月 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.commons.json.parser.deserializer;

import static com.elancom.framework.commons.json.util.ASMUtils.getDesc;
import static com.elancom.framework.commons.json.util.ASMUtils.getType;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicLong;

import com.elancom.framework.commons.json.JSONException;
import com.elancom.framework.commons.json.asm.ASMException;
import com.elancom.framework.commons.json.asm.ClassWriter;
import com.elancom.framework.commons.json.asm.FieldVisitor;
import com.elancom.framework.commons.json.asm.Label;
import com.elancom.framework.commons.json.asm.MethodVisitor;
import com.elancom.framework.commons.json.asm.Opcodes;
import com.elancom.framework.commons.json.parser.DefaultJSONParser;
import com.elancom.framework.commons.json.parser.DefaultJSONParser.ResolveTask;
import com.elancom.framework.commons.json.parser.Feature;
import com.elancom.framework.commons.json.parser.JSONLexer;
import com.elancom.framework.commons.json.parser.JSONScanner;
import com.elancom.framework.commons.json.parser.JSONToken;
import com.elancom.framework.commons.json.parser.ParseContext;
import com.elancom.framework.commons.json.parser.ParserConfig;
import com.elancom.framework.commons.json.parser.SymbolTable;
import com.elancom.framework.commons.json.parser.deserializer.ASMJavaBeanDeserializer.InnerJavaBeanDeserializer;
import com.elancom.framework.commons.json.util.ASMClassLoader;
import com.elancom.framework.commons.json.util.DeserializeBeanInfo;
import com.elancom.framework.commons.json.util.FieldInfo;

public class ASMDeserializerFactory implements Opcodes {

	private static final ASMDeserializerFactory instance = new ASMDeserializerFactory();

	private final ASMClassLoader classLoader = new ASMClassLoader();

	private final AtomicLong seed = new AtomicLong();

	public String getGenClassName(Class<?> clazz) {
		return "Fastjson_ASM_" + clazz.getSimpleName() + "_" + seed.incrementAndGet();
	}

	public String getGenFieldDeserializer(Class<?> clazz, FieldInfo fieldInfo) {
		String name = "Fastjson_ASM__Field_" + clazz.getSimpleName();
		name += "_" + fieldInfo.getName() + "_" + seed.incrementAndGet();

		return name;
	}

	public ASMDeserializerFactory() {

	}

	public final static ASMDeserializerFactory getInstance() {
		return instance;
	}

	public ObjectDeserializer createJavaBeanDeserializer(ParserConfig config, Class<?> clazz) throws Exception {
		if (clazz.isPrimitive()) {
			throw new IllegalArgumentException("not support type :" + clazz.getName());
		}

		final String className = getGenClassName(clazz);

		final ClassWriter cw = new ClassWriter();
		cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, getType(ASMJavaBeanDeserializer.class), null);

		final DeserializeBeanInfo beanInfo = DeserializeBeanInfo.computeSetters(clazz);

		_init(cw, new Context(className, config, beanInfo, 3));
		_createInstance(cw, new Context(className, config, beanInfo, 3));
		_deserialze(cw, new Context(className, config, beanInfo, 4));

		final byte[] code = cw.toByteArray();

		// org.apache.commons.io.IOUtils.write(code, new java.io.FileOutputStream(
		// "/usr/alibaba/workspace-3.7/fastjson-asm/target/classes/"
		// + className + ".class"));

		final Class<?> exampleClass = classLoader.defineClassPublic(className, code, 0, code.length);

		final Constructor<?> constructor = exampleClass.getConstructor(ParserConfig.class, Class.class);
		final Object instance = constructor.newInstance(config, clazz);

		return (ObjectDeserializer) instance;
	}

	void _deserialze(ClassWriter cw, Context context) {
		if (context.getFieldInfoList().size() == 0) {
			return;
		}

		for (final FieldInfo fieldInfo : context.getFieldInfoList()) {
			final Class<?> fieldClass = fieldInfo.getFieldClass();
			final Type fieldType = fieldInfo.getFieldType();

			if (fieldClass == char.class) {
				return;
			}

			if (Collection.class.isAssignableFrom(fieldClass)) {
				if (fieldType instanceof ParameterizedType) {
					final Type itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
					if (itemType instanceof Class) {
						continue;
					} else {
						return;
					}
				} else {
					return;
				}
			}
		}

		Collections.sort(context.getFieldInfoList());

		final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "deserialze", "(" + getDesc(DefaultJSONParser.class) + getDesc(Type.class)
				+ "Ljava/lang/Object;)Ljava/lang/Object;", null, null);

		final Label reset_ = new Label();
		final Label super_ = new Label();
		final Label return_ = new Label();
		final Label end_ = new Label();

		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getLexer", "()" + getDesc(JSONLexer.class));
		mw.visitTypeInsn(CHECKCAST, getType(JSONScanner.class)); // cast
		mw.visitVarInsn(ASTORE, context.var("lexer"));

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitFieldInsn(GETSTATIC, getType(Feature.class), "SortFeidFastMatch", "L" + getType(Feature.class) + ";");
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "isEnabled", "(" + "L" + getType(Feature.class) + ";" + ")Z");
		mw.visitJumpInsn(IFEQ, super_);

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitLdcInsn(context.getClazz().getName());
		// parser.setResolveStatus

		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanType", "(Ljava/lang/String;)I");

		mw.visitFieldInsn(GETSTATIC, getType(JSONScanner.class), "NOT_MATCH", "I");
		mw.visitJumpInsn(IF_ICMPEQ, super_);

		// matchType

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "getBufferPosition", "()I");
		mw.visitVarInsn(ISTORE, context.var("mark"));

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "getCurrent", "()C");
		mw.visitVarInsn(ISTORE, context.var("mark_ch"));

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitVarInsn(ISTORE, context.var("mark_token"));

		final Constructor<?> defaultConstructor = context.getBeanInfo().getDefaultConstructor();

		// create instance
		if (context.getClazz().isInterface()) {
			mw.visitVarInsn(ALOAD, 0);
			mw.visitVarInsn(ALOAD, 1);
			mw.visitMethodInsn(INVOKESPECIAL, getType(ASMJavaBeanDeserializer.class), "createInstance", "(" + getDesc(DefaultJSONParser.class)
					+ ")Ljava/lang/Object;");
			mw.visitTypeInsn(CHECKCAST, getType(context.getClazz())); // cast
			mw.visitVarInsn(ASTORE, context.var("instance"));
		} else {
			if (defaultConstructor != null) {
				if (Modifier.isPublic(defaultConstructor.getModifiers())) {
					mw.visitTypeInsn(NEW, getType(context.getClazz()));
					mw.visitInsn(DUP);
					mw.visitMethodInsn(INVOKESPECIAL, getType(context.getClazz()), "<init>", "()V");

					mw.visitVarInsn(ASTORE, context.var("instance"));
				} else {
					mw.visitVarInsn(ALOAD, 0);
					mw.visitVarInsn(ALOAD, 1);
					mw.visitMethodInsn(INVOKESPECIAL, getType(ASMJavaBeanDeserializer.class), "createInstance", "(" + getDesc(DefaultJSONParser.class)
							+ ")Ljava/lang/Object;");
					mw.visitTypeInsn(CHECKCAST, getType(context.getClazz())); // cast
					mw.visitVarInsn(ASTORE, context.var("instance"));
				}
			} else {
				mw.visitInsn(ACONST_NULL);
				mw.visitTypeInsn(CHECKCAST, getType(context.getClazz())); // cast
				mw.visitVarInsn(ASTORE, context.var("instance"));
			}
		}

		{
			mw.visitVarInsn(ALOAD, 1); // parser
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getContext", "()Lcom/elancom/framework/commons/json/parser/ParseContext;");
			mw.visitVarInsn(ASTORE, context.var("context"));

			mw.visitVarInsn(ALOAD, 1); // parser
			mw.visitVarInsn(ALOAD, context.var("context"));
			mw.visitVarInsn(ALOAD, context.var("instance"));
			mw.visitVarInsn(ALOAD, 3); // fieldName
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "setContext",
					"(Lcom/elancom/framework/commons/json/parser/ParseContext;Ljava/lang/Object;Ljava/lang/Object;)Lcom/elancom/framework/commons/json/parser/ParseContext;");
			mw.visitVarInsn(ASTORE, context.var("childContext"));
		}

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitFieldInsn(GETFIELD, getType(JSONScanner.class), "matchStat", "I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONScanner.class), "END", "I");
		mw.visitJumpInsn(IF_ICMPEQ, return_);

		for (int i = 0, size = context.getFieldInfoList().size(); i < size; ++i) {
			final FieldInfo fieldInfo = context.getFieldInfoList().get(i);
			final Class<?> fieldClass = fieldInfo.getFieldClass();
			final Type fieldType = fieldInfo.getFieldType();

			mw.visitVarInsn(ALOAD, context.var("lexer"));
			mw.visitVarInsn(ALOAD, 0);
			mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_prefix__", "[C");
			if (fieldClass == boolean.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldBoolean", "([C)Z");
				mw.visitVarInsn(ISTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == byte.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldInt", "([C)I");
				mw.visitVarInsn(ISTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == short.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldInt", "([C)I");
				mw.visitVarInsn(ISTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == int.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldInt", "([C)I");
				mw.visitVarInsn(ISTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == long.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldLong", "([C)J");
				mw.visitVarInsn(LSTORE, context.var(fieldInfo.getName() + "_asm", 2));

			} else if (fieldClass == float.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldFloat", "([C)F");
				mw.visitVarInsn(FSTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == double.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldDouble", "([C)D");
				mw.visitVarInsn(DSTORE, context.var(fieldInfo.getName() + "_asm", 2));

			} else if (fieldClass == String.class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldString", "([C)Ljava/lang/String;");
				mw.visitInsn(DUP);

				final Label endCheck_ = new Label();
				mw.visitJumpInsn(IFNONNULL, endCheck_);

				mw.visitVarInsn(ALOAD, 1);
				mw.visitFieldInsn(GETSTATIC, getType(Feature.class), "InitStringFieldAsEmpty", "L" + getType(Feature.class) + ";");
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "isEnabled", "(" + "L" + getType(Feature.class) + ";" + ")Z");
				mw.visitJumpInsn(IFEQ, endCheck_);

				mw.visitInsn(POP);
				mw.visitLdcInsn("");

				mw.visitLabel(endCheck_);

				mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));

			} else if (fieldClass == byte[].class) {
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldByteArray", "([C)[B");
				mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass.isEnum()) {
				final Label enumNull_ = new Label();
				mw.visitInsn(ACONST_NULL);
				mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
				mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));

				mw.visitVarInsn(ALOAD, 1);
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getSymbolTable", "()" + getDesc(SymbolTable.class));

				mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldSymbol", "([C" + getDesc(SymbolTable.class) + ")Ljava/lang/String;");
				mw.visitInsn(DUP);
				mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm_enumName"));

				mw.visitJumpInsn(IFNULL, enumNull_);
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm_enumName"));
				mw.visitMethodInsn(INVOKESTATIC, getType(fieldClass), "valueOf", "(Ljava/lang/String;)" + getDesc(fieldClass));
				mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));
				mw.visitLabel(enumNull_);

			} else if (Collection.class.isAssignableFrom(fieldClass)) {

				final Type actualTypeArgument = ((ParameterizedType) fieldType).getActualTypeArguments()[0];

				if (actualTypeArgument instanceof Class) {
					final Class<?> itemClass = (Class<?>) actualTypeArgument;

					if (!Modifier.isPublic(itemClass.getModifiers())) {
						throw new ASMException("can not create ASMParser");
					}

					if (itemClass == String.class) {
						mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "scanFieldStringArray", "([C)" + getDesc(ArrayList.class));
						mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));
					} else {
						_deserialze_list_obj(context, mw, reset_, fieldInfo, fieldClass, itemClass);

						if (i == size - 1) {
							_deserialize_endCheck(context, mw, reset_);
						}
						continue;
					}
				} else {
					throw new ASMException("can not create ASMParser");
				}

			} else {
				_deserialze_obj(context, mw, reset_, fieldInfo, fieldClass);

				if (i == size - 1) {
					_deserialize_endCheck(context, mw, reset_);
				}

				continue;
			}

			mw.visitVarInsn(ALOAD, context.var("lexer"));
			mw.visitFieldInsn(GETFIELD, getType(JSONScanner.class), "matchStat", "I");
			mw.visitFieldInsn(GETSTATIC, getType(JSONScanner.class), "NOT_MATCH", "I");
			mw.visitJumpInsn(IF_ICMPEQ, reset_);

			if (i == size - 1) {
				mw.visitVarInsn(ALOAD, context.var("lexer"));
				mw.visitFieldInsn(GETFIELD, getType(JSONScanner.class), "matchStat", "I");
				mw.visitFieldInsn(GETSTATIC, getType(JSONScanner.class), "END", "I");
				mw.visitJumpInsn(IF_ICMPNE, reset_);
			}
		}

		mw.visitLabel(end_);

		if (!context.getClazz().isInterface() && !Modifier.isAbstract(context.getClazz().getModifiers())) {
			if (defaultConstructor != null) {
				_batchSet(context, mw);
			} else {
				final Constructor<?> creatorConstructor = context.getBeanInfo().getCreatorConstructor();
				if (creatorConstructor != null) {
					mw.visitTypeInsn(NEW, getType(context.getClazz()));
					mw.visitInsn(DUP);

					_loadCreatorParameters(context, mw);

					mw.visitMethodInsn(INVOKESPECIAL, getType(context.getClazz()), "<init>", getDesc(creatorConstructor));
					mw.visitVarInsn(ASTORE, context.var("instance"));
				} else {
					final Method factoryMethod = context.getBeanInfo().getFactoryMethod();
					if (factoryMethod != null) {
						_loadCreatorParameters(context, mw);
						mw.visitMethodInsn(INVOKESTATIC, getType(factoryMethod.getDeclaringClass()), factoryMethod.getName(), getDesc(factoryMethod));
						mw.visitVarInsn(ASTORE, context.var("instance"));
					} else {
						throw new JSONException("TODO");
					}
				}
			}
		}

		mw.visitLabel(return_);

		_setContext(context, mw, true);
		mw.visitVarInsn(ALOAD, context.var("instance"));
		mw.visitInsn(ARETURN);

		mw.visitLabel(reset_);

		// void reset(int mark, char mark_ch)
		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitVarInsn(ILOAD, context.var("mark"));
		mw.visitVarInsn(ILOAD, context.var("mark_ch"));
		mw.visitVarInsn(ILOAD, context.var("mark_token"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "reset", "(ICI)V");

		_setContext(context, mw, false);

		mw.visitLabel(super_);
		mw.visitVarInsn(ALOAD, 0);
		mw.visitVarInsn(ALOAD, 1);
		mw.visitVarInsn(ALOAD, 2);
		mw.visitVarInsn(ALOAD, 3);
		mw.visitMethodInsn(INVOKESPECIAL, getType(ASMJavaBeanDeserializer.class), "deserialze", "(" + getDesc(DefaultJSONParser.class) + getDesc(Type.class)
				+ "Ljava/lang/Object;)Ljava/lang/Object;");
		mw.visitInsn(ARETURN);

		int maxStack = 4;
		final Constructor<?> creatorConstructor = context.getBeanInfo().getCreatorConstructor();
		if (creatorConstructor != null) {
			int constructorTypeStack = 2;
			for (final Class<?> type : creatorConstructor.getParameterTypes()) {
				if (type == long.class || type == double.class) {
					constructorTypeStack += 2;
				} else {
					constructorTypeStack++;
				}
			}
			if (maxStack < constructorTypeStack) {
				maxStack = constructorTypeStack;
			}
		} else {
			final Method factoryMethod = context.getBeanInfo().getFactoryMethod();
			if (factoryMethod != null) {
				int paramStacks = 2;
				for (final Class<?> type : factoryMethod.getParameterTypes()) {
					if (type == long.class || type == double.class) {
						paramStacks += 2;
					} else {
						paramStacks++;
					}
				}
				if (maxStack < paramStacks) {
					maxStack = paramStacks;
				}
			}
		}

		mw.visitMaxs(maxStack, context.getVariantCount());
		mw.visitEnd();
	}

	private void _loadCreatorParameters(Context context, MethodVisitor mw) {
		final List<FieldInfo> fieldInfoList = context.getBeanInfo().getFieldList();

		for (int i = 0, size = fieldInfoList.size(); i < size; ++i) {
			final FieldInfo fieldInfo = fieldInfoList.get(i);
			final Class<?> fieldClass = fieldInfo.getFieldClass();
			final Type fieldType = fieldInfo.getFieldType();

			if (fieldClass == boolean.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == byte.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == short.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == int.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == long.class) {
				mw.visitVarInsn(LLOAD, context.var(fieldInfo.getName() + "_asm", 2));
			} else if (fieldClass == float.class) {
				mw.visitVarInsn(FLOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == double.class) {
				mw.visitVarInsn(DLOAD, context.var(fieldInfo.getName() + "_asm", 2));
			} else if (fieldClass == String.class) {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass.isEnum()) {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (Collection.class.isAssignableFrom(fieldClass)) {
				final Type itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
				if (itemType == String.class) {
					mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
					mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
				} else {
					mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
				}
			} else {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			}
		}
	}

	private void _batchSet(Context context, MethodVisitor mw) {
		for (int i = 0, size = context.getFieldInfoList().size(); i < size; ++i) {
			final FieldInfo fieldInfo = context.getFieldInfoList().get(i);
			final Class<?> fieldClass = fieldInfo.getFieldClass();
			final Type fieldType = fieldInfo.getFieldType();

			mw.visitVarInsn(ALOAD, context.var("instance"));
			if (fieldClass == boolean.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == byte.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == short.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == int.class) {
				mw.visitVarInsn(ILOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == long.class) {
				mw.visitVarInsn(LLOAD, context.var(fieldInfo.getName() + "_asm", 2));
				mw.visitMethodInsn(INVOKEVIRTUAL, getType(context.getClazz()), fieldInfo.getMethod().getName(), "(J)V");
				continue;
			} else if (fieldClass == float.class) {
				mw.visitVarInsn(FLOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass == double.class) {
				mw.visitVarInsn(DLOAD, context.var(fieldInfo.getName() + "_asm", 2));
			} else if (fieldClass == String.class) {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (fieldClass.isEnum()) {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			} else if (Collection.class.isAssignableFrom(fieldClass)) {
				final Type itemType = ((ParameterizedType) fieldType).getActualTypeArguments()[0];
				if (itemType == String.class) {
					mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
					mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
				} else {
					mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
				}
			} else {
				mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			}

			int INVAKE_TYPE;
			if (context.getClazz().isInterface()) {
				INVAKE_TYPE = INVOKEINTERFACE;
			} else {
				INVAKE_TYPE = INVOKEVIRTUAL;
			}
			if (fieldInfo.getMethod() != null) {
				mw.visitMethodInsn(INVAKE_TYPE, getType(fieldInfo.getDeclaringClass()), fieldInfo.getMethod().getName(), getDesc(fieldInfo.getMethod()));
			} else {
				mw.visitFieldInsn(PUTFIELD, getType(fieldInfo.getDeclaringClass()), fieldInfo.getField().getName(), getDesc(fieldInfo.getFieldClass()));
			}
		}
	}

	private void _setContext(Context context, MethodVisitor mw, boolean setObject) {
		mw.visitVarInsn(ALOAD, 1); // parser
		mw.visitVarInsn(ALOAD, context.var("context"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "setContext", "(Lcom/elancom/framework/commons/json/parser/ParseContext;)V");

		// TODO childContext is null
		if (setObject) {
			final Label endIf_ = new Label();
			mw.visitVarInsn(ALOAD, context.var("childContext"));
			mw.visitJumpInsn(IFNULL, endIf_);

			mw.visitVarInsn(ALOAD, context.var("childContext"));
			mw.visitVarInsn(ALOAD, context.var("instance"));
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(ParseContext.class), "setObject", "(Ljava/lang/Object;)V");

			mw.visitLabel(endIf_);
		}
	}

	private void _deserialize_endCheck(Context context, MethodVisitor mw, Label reset_) {
		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "RBRACE", "I");
		mw.visitJumpInsn(IF_ICMPNE, reset_);

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "COMMA", "I");
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "nextToken", "(I)V");
	}

	private void _deserialze_list_obj(Context context, MethodVisitor mw, Label reset_, FieldInfo fieldInfo, Class<?> fieldClass, Class<?> itemType) {
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "matchField", "([C)Z");
		mw.visitJumpInsn(IFEQ, reset_);

		final Label notNull_ = new Label();
		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_list_item_deser__", getDesc(ObjectDeserializer.class));
		mw.visitJumpInsn(IFNONNULL, notNull_);

		mw.visitVarInsn(ALOAD, 0);

		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getConfig", "()" + getDesc(ParserConfig.class));
		mw.visitLdcInsn(com.elancom.framework.commons.json.asm.Type.getType(getDesc(itemType)));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(ParserConfig.class), "getDeserializer", "(" + getDesc(Type.class) + ")" + getDesc(ObjectDeserializer.class));

		mw.visitFieldInsn(PUTFIELD, context.getClassName(), fieldInfo.getName() + "_asm_list_item_deser__", getDesc(ObjectDeserializer.class));

		mw.visitLabel(notNull_);

		// if (lexer.token() != JSONToken.LBRACKET) reset
		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "LBRACKET", "I");
		mw.visitJumpInsn(IF_ICMPNE, reset_);

		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_list_item_deser__", getDesc(ObjectDeserializer.class));
		mw.visitMethodInsn(INVOKEINTERFACE, getType(ObjectDeserializer.class), "getFastMatchToken", "()I");
		mw.visitVarInsn(ISTORE, context.var("fastMatchToken"));

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitVarInsn(ILOAD, context.var("fastMatchToken"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "nextToken", "(I)V");

		if (fieldClass.isAssignableFrom(ArrayList.class)) {
			mw.visitTypeInsn(NEW, getType(ArrayList.class));
			mw.visitInsn(DUP);
			mw.visitMethodInsn(INVOKESPECIAL, getType(ArrayList.class), "<init>", "()V");
		} else if (fieldClass.isAssignableFrom(LinkedList.class)) {
			mw.visitTypeInsn(NEW, getType(LinkedList.class));
			mw.visitInsn(DUP);
			mw.visitMethodInsn(INVOKESPECIAL, getType(LinkedList.class), "<init>", "()V");
		} else if (fieldClass.isAssignableFrom(HashSet.class)) {
			mw.visitTypeInsn(NEW, getType(HashSet.class));
			mw.visitInsn(DUP);
			mw.visitMethodInsn(INVOKESPECIAL, getType(HashSet.class), "<init>", "()V");
		} else if (fieldClass.isAssignableFrom(TreeSet.class)) {
			mw.visitTypeInsn(NEW, getType(TreeSet.class));
			mw.visitInsn(DUP);
			mw.visitMethodInsn(INVOKESPECIAL, getType(TreeSet.class), "<init>", "()V");
		} else {
			mw.visitTypeInsn(NEW, getType(fieldClass));
			mw.visitInsn(DUP);
			mw.visitMethodInsn(INVOKESPECIAL, getType(fieldClass), "<init>", "()V");
		}

		mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
		mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));

		{ // setContext
			mw.visitVarInsn(ALOAD, 1); // parser
			mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
			mw.visitLdcInsn(fieldInfo.getName());
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "setContext",
					"(Ljava/lang/Object;Ljava/lang/Object;)Lcom/elancom/framework/commons/json/parser/ParseContext;");
			mw.visitInsn(POP);
		}

		final Label loop_ = new Label();
		final Label loop_end_ = new Label();

		// for (;;) {
		mw.visitInsn(ICONST_0);
		mw.visitVarInsn(ISTORE, context.var("i"));
		mw.visitLabel(loop_);
		// if (lexer.isEnabled(Feature.AllowArbitraryCommas)) {
		// while (lexer.token() == JSONToken.COMMA) {
		// lexer.nextToken();
		// continue;
		// }
		// }
		// if (lexer.token() == JSONToken.RBRACKET) {
		// break;
		// }
		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "RBRACKET", "I");
		mw.visitJumpInsn(IF_ICMPEQ, loop_end_);

		// Object value = itemDeserializer.deserialze(parser, null);
		// array.add(value);

		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_list_item_deser__", getDesc(ObjectDeserializer.class));
		mw.visitVarInsn(ALOAD, 1);
		mw.visitInsn(ACONST_NULL);
		mw.visitVarInsn(ILOAD, context.var("i"));
		mw.visitMethodInsn(INVOKESTATIC, getType(Integer.class), "valueOf", "(I)Ljava/lang/Integer;");
		mw.visitMethodInsn(INVOKEINTERFACE, getType(ObjectDeserializer.class), "deserialze",
				"(Lcom/elancom/framework/commons/json/parser/DefaultJSONParser;Ljava/lang/reflect/Type;Ljava/lang/Object;)Ljava/lang/Object;");
		mw.visitVarInsn(ASTORE, context.var("list_item_value"));

		mw.visitIincInsn(context.var("i"), 1);

		mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
		mw.visitVarInsn(ALOAD, context.var("list_item_value"));
		if (fieldClass.isInterface()) {
			mw.visitMethodInsn(INVOKEINTERFACE, getType(fieldClass), "add", "(Ljava/lang/Object;)Z");
		} else {
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(fieldClass), "add", "(Ljava/lang/Object;)Z");
		}
		mw.visitInsn(POP);

		mw.visitVarInsn(ALOAD, 1);
		mw.visitVarInsn(ALOAD, context.var(fieldInfo.getName() + "_asm"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "checkListResolve", "(Ljava/util/Collection;)V");

		// if (lexer.token() == JSONToken.COMMA) {
		// lexer.nextToken(itemDeserializer.getFastMatchToken());
		// continue;
		// }
		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "COMMA", "I");
		mw.visitJumpInsn(IF_ICMPNE, loop_);

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitVarInsn(ILOAD, context.var("fastMatchToken"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "nextToken", "(I)V");
		mw.visitJumpInsn(GOTO, loop_);

		mw.visitLabel(loop_end_);

		{ // setContext
			mw.visitVarInsn(ALOAD, 1); // parser
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "popContext", "()V");
		}

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "token", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "RBRACKET", "I");
		mw.visitJumpInsn(IF_ICMPNE, reset_);

		mw.visitVarInsn(ALOAD, context.var("lexer"));
		mw.visitFieldInsn(GETSTATIC, getType(JSONToken.class), "COMMA", "I");
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "nextToken", "(I)V");
		// lexer.nextToken(JSONToken.COMMA);

	}

	private void _deserialze_obj(Context context, MethodVisitor mw, Label reset_, FieldInfo fieldInfo, Class<?> fieldClass) {
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JSONScanner.class), "matchField", "([C)Z");
		mw.visitJumpInsn(IFEQ, reset_);

		final Label notNull_ = new Label();
		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_deser__", getDesc(ObjectDeserializer.class));
		mw.visitJumpInsn(IFNONNULL, notNull_);

		mw.visitVarInsn(ALOAD, 0);

		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getConfig", "()" + getDesc(ParserConfig.class));
		mw.visitLdcInsn(com.elancom.framework.commons.json.asm.Type.getType(getDesc(fieldInfo.getFieldClass())));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(ParserConfig.class), "getDeserializer", "(" + getDesc(Type.class) + ")" + getDesc(ObjectDeserializer.class));

		mw.visitFieldInsn(PUTFIELD, context.getClassName(), fieldInfo.getName() + "_asm_deser__", getDesc(ObjectDeserializer.class));

		mw.visitLabel(notNull_);

		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, context.getClassName(), fieldInfo.getName() + "_asm_deser__", getDesc(ObjectDeserializer.class));
		mw.visitVarInsn(ALOAD, 1);
		if (fieldInfo.getFieldType() instanceof Class) {
			mw.visitLdcInsn(com.elancom.framework.commons.json.asm.Type.getType(getDesc(fieldInfo.getFieldClass())));
		} else {
			mw.visitVarInsn(ALOAD, 0);
			mw.visitLdcInsn(fieldInfo.getName());
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(ASMJavaBeanDeserializer.class), "getFieldType", "(Ljava/lang/String;)Ljava/lang/reflect/Type;");
		}
		mw.visitLdcInsn(fieldInfo.getName());
		mw.visitMethodInsn(INVOKEINTERFACE, getType(ObjectDeserializer.class), "deserialze", "(" + getDesc(DefaultJSONParser.class) + getDesc(Type.class)
				+ "Ljava/lang/Object;)Ljava/lang/Object;");
		mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
		mw.visitVarInsn(ASTORE, context.var(fieldInfo.getName() + "_asm"));

		final Label _end_if = new Label();

		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getResolveStatus", "()I");
		mw.visitFieldInsn(GETSTATIC, getType(DefaultJSONParser.class), "NeedToResolve", "I");
		mw.visitJumpInsn(IF_ICMPNE, _end_if);

		// ResolveTask task = parser.getLastResolveTask();
		// task.setFieldDeserializer(this);
		// task.setOwnerContext(parser.getContext());

		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getLastResolveTask", "()" + getDesc(ResolveTask.class));
		mw.visitVarInsn(ASTORE, context.var("resolveTask"));

		mw.visitVarInsn(ALOAD, context.var("resolveTask"));
		mw.visitVarInsn(ALOAD, 1);
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "getContext", "()" + getDesc(ParseContext.class));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(ResolveTask.class), "setOwnerContext", "(" + getDesc(ParseContext.class) + ")V");

		mw.visitVarInsn(ALOAD, context.var("resolveTask"));
		mw.visitVarInsn(ALOAD, 0);
		mw.visitLdcInsn(fieldInfo.getName());
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(ASMJavaBeanDeserializer.class), "getFieldDeserializer", "(Ljava/lang/String;)"
				+ getDesc(FieldDeserializer.class));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(ResolveTask.class), "setFieldDeserializer", "(" + getDesc(FieldDeserializer.class) + ")V");

		mw.visitVarInsn(ALOAD, 1);
		mw.visitFieldInsn(GETSTATIC, getType(DefaultJSONParser.class), "NONE", "I");
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(DefaultJSONParser.class), "setResolveStatus", "(I)V");

		mw.visitLabel(_end_if);

	}

	public FieldDeserializer createFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo) throws Exception {
		final Class<?> fieldClass = fieldInfo.getFieldClass();

		if (fieldClass == int.class || fieldClass == long.class || fieldClass == String.class) {
			return createStringFieldDeserializer(mapping, clazz, fieldInfo);
		}

		final FieldDeserializer fieldDeserializer = mapping.createFieldDeserializerWithoutASM(mapping, clazz, fieldInfo);
		return fieldDeserializer;
	}

	public FieldDeserializer createStringFieldDeserializer(ParserConfig mapping, Class<?> clazz, FieldInfo fieldInfo) throws Exception {
		final Class<?> fieldClass = fieldInfo.getFieldClass();
		final Method method = fieldInfo.getMethod();

		final String className = getGenFieldDeserializer(clazz, fieldInfo);

		final ClassWriter cw = new ClassWriter();
		Class<?> superClass;
		if (fieldClass == int.class) {
			superClass = IntegerFieldDeserializer.class;
		} else if (fieldClass == long.class) {
			superClass = LongFieldDeserializer.class;
		} else {
			superClass = StringFieldDeserializer.class;
		}

		int INVAKE_TYPE;
		if (clazz.isInterface()) {
			INVAKE_TYPE = INVOKEINTERFACE;
		} else {
			INVAKE_TYPE = INVOKEVIRTUAL;
		}

		cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, getType(superClass), null);

		{
			final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "(" + getDesc(ParserConfig.class) + getDesc(Class.class) + getDesc(FieldInfo.class)
					+ ")V", null, null);
			mw.visitVarInsn(ALOAD, 0);
			mw.visitVarInsn(ALOAD, 1);
			mw.visitVarInsn(ALOAD, 2);
			mw.visitVarInsn(ALOAD, 3);
			mw.visitMethodInsn(INVOKESPECIAL, getType(superClass), "<init>", "(" + getDesc(ParserConfig.class) + getDesc(Class.class)
					+ getDesc(FieldInfo.class) + ")V");

			mw.visitInsn(RETURN);
			mw.visitMaxs(4, 6);
			mw.visitEnd();
		}

		if (method != null) {
			if (fieldClass == int.class) {
				final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "setValue", "(" + getDesc(Object.class) + "I)V", null, null);
				mw.visitVarInsn(ALOAD, 1);
				mw.visitTypeInsn(CHECKCAST, getType(method.getDeclaringClass())); // cast
				mw.visitVarInsn(ILOAD, 2);
				mw.visitMethodInsn(INVAKE_TYPE, getType(method.getDeclaringClass()), method.getName(), "(I)V");

				mw.visitInsn(RETURN);
				mw.visitMaxs(3, 3);
				mw.visitEnd();
			} else if (fieldClass == long.class) {
				final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "setValue", "(" + getDesc(Object.class) + "J)V", null, null);
				mw.visitVarInsn(ALOAD, 1);
				mw.visitTypeInsn(CHECKCAST, getType(method.getDeclaringClass())); // cast
				mw.visitVarInsn(LLOAD, 2);
				mw.visitMethodInsn(INVAKE_TYPE, getType(method.getDeclaringClass()), method.getName(), "(J)V");

				mw.visitInsn(RETURN);
				mw.visitMaxs(3, 4);
				mw.visitEnd();
			} else {
				// public void setValue(Object object, Object value)
				final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "setValue", "(" + getDesc(Object.class) + getDesc(Object.class) + ")V", null, null);
				mw.visitVarInsn(ALOAD, 1);
				mw.visitTypeInsn(CHECKCAST, getType(method.getDeclaringClass())); // cast
				mw.visitVarInsn(ALOAD, 2);
				mw.visitTypeInsn(CHECKCAST, getType(fieldClass)); // cast
				mw.visitMethodInsn(INVAKE_TYPE, getType(method.getDeclaringClass()), method.getName(), "(" + getDesc(fieldClass) + ")V");

				mw.visitInsn(RETURN);
				mw.visitMaxs(3, 3);
				mw.visitEnd();
			}
		}

		final byte[] code = cw.toByteArray();

		final Class<?> exampleClass = classLoader.defineClassPublic(className, code, 0, code.length);

		final Constructor<?> constructor = exampleClass.getConstructor(ParserConfig.class, Class.class, FieldInfo.class);
		final Object instance = constructor.newInstance(mapping, clazz, fieldInfo);

		return (FieldDeserializer) instance;
	}

	static class Context {

		private int variantIndex = 5;

		private final Map<String, Integer> variants = new HashMap<String, Integer>();

		private final Class<?> clazz;
		private final DeserializeBeanInfo beanInfo;
		private final String className;
		private final List<FieldInfo> fieldInfoList;

		public Context(String className, ParserConfig config, DeserializeBeanInfo beanInfo, int initVariantIndex) {
			this.className = className;
			clazz = beanInfo.getClazz();
			variantIndex = initVariantIndex;
			this.beanInfo = beanInfo;
			fieldInfoList = new ArrayList<FieldInfo>(beanInfo.getFieldList());
		}

		public String getClassName() {
			return className;
		}

		public List<FieldInfo> getFieldInfoList() {
			return fieldInfoList;
		}

		public DeserializeBeanInfo getBeanInfo() {
			return beanInfo;
		}

		public Class<?> getClazz() {
			return clazz;
		}

		public int getVariantCount() {
			return variantIndex;
		}

		public int var(String name, int increment) {
			Integer i = variants.get(name);
			if (i == null) {
				variants.put(name, variantIndex);
				variantIndex += increment;
			}
			i = variants.get(name);
			return i.intValue();
		}

		public int var(String name) {
			Integer i = variants.get(name);
			if (i == null) {
				variants.put(name, variantIndex++);
			}
			i = variants.get(name);
			return i.intValue();
		}
	}

	private void _init(ClassWriter cw, Context context) {
		for (int i = 0, size = context.getFieldInfoList().size(); i < size; ++i) {
			final FieldInfo fieldInfo = context.getFieldInfoList().get(i);

			// public FieldVisitor visitField(final int access, final String name, final String desc, final String
			// signature, final Object value) {
			final FieldVisitor fw = cw.visitField(ACC_PUBLIC, fieldInfo.getName() + "_asm_prefix__", "[C");
			fw.visitEnd();
		}

		for (int i = 0, size = context.getFieldInfoList().size(); i < size; ++i) {
			final FieldInfo fieldInfo = context.getFieldInfoList().get(i);
			final Class<?> fieldClass = fieldInfo.getFieldClass();

			if (fieldClass.isPrimitive()) {
				continue;
			}

			if (fieldClass.isEnum()) {

			} else if (Collection.class.isAssignableFrom(fieldClass)) {
				final FieldVisitor fw = cw.visitField(ACC_PUBLIC, fieldInfo.getName() + "_asm_list_item_deser__", getDesc(ObjectDeserializer.class));
				fw.visitEnd();
			} else {
				final FieldVisitor fw = cw.visitField(ACC_PUBLIC, fieldInfo.getName() + "_asm_deser__", getDesc(ObjectDeserializer.class));
				fw.visitEnd();
			}
		}

		final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "(" + getDesc(ParserConfig.class) + getDesc(Class.class) + ")V", null, null);
		mw.visitVarInsn(ALOAD, 0);
		mw.visitVarInsn(ALOAD, 1);
		mw.visitVarInsn(ALOAD, 2);
		mw.visitMethodInsn(INVOKESPECIAL, getType(ASMJavaBeanDeserializer.class), "<init>", "(" + getDesc(ParserConfig.class) + getDesc(Class.class) + ")V");

		mw.visitVarInsn(ALOAD, 0);
		mw.visitFieldInsn(GETFIELD, getType(ASMJavaBeanDeserializer.class), "serializer", getDesc(InnerJavaBeanDeserializer.class));
		mw.visitMethodInsn(INVOKEVIRTUAL, getType(JavaBeanDeserializer.class), "getFieldDeserializerMap", "()" + getDesc(Map.class));
		mw.visitInsn(POP);

		// init fieldNamePrefix
		for (int i = 0, size = context.getFieldInfoList().size(); i < size; ++i) {
			final FieldInfo fieldInfo = context.getFieldInfoList().get(i);

			mw.visitVarInsn(ALOAD, 0);
			mw.visitLdcInsn("\"" + fieldInfo.getName() + "\":"); // public char[] toCharArray()
			mw.visitMethodInsn(INVOKEVIRTUAL, getType(String.class), "toCharArray", "()" + getDesc(char[].class));
			mw.visitFieldInsn(PUTFIELD, context.getClassName(), fieldInfo.getName() + "_asm_prefix__", "[C");

		}

		mw.visitInsn(RETURN);
		mw.visitMaxs(4, 4);
		mw.visitEnd();
	}

	private void _createInstance(ClassWriter cw, Context context) {
		final MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "createInstance", "(" + getDesc(DefaultJSONParser.class) + getDesc(Type.class)
				+ ")Ljava/lang/Object;", null, null);

		mw.visitTypeInsn(NEW, getType(context.getClazz()));
		mw.visitInsn(DUP);
		mw.visitMethodInsn(INVOKESPECIAL, getType(context.getClazz()), "<init>", "()V");

		mw.visitInsn(ARETURN);
		mw.visitMaxs(3, 3);
		mw.visitEnd();
	}

}
